package ru.mcfr.oxygen.framework.operations.table;

import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import ro.sync.ecss.extensions.api.*;
import ro.sync.ecss.extensions.api.access.AuthorTableAccess;
import ro.sync.ecss.extensions.api.node.AuthorDocumentFragment;
import ro.sync.ecss.extensions.api.node.AuthorNode;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringWriter;

/**
 * Created by IntelliJ IDEA.
 * User: ws
 * Date: 11.03.11
 * Time: 12:34
 * To change this template use File | Settings | File Templates.
 */
public class JoinCellInRowOperation implements AuthorOperation{

    private static Logger logger = Logger.getLogger(JoinCellInRowOperation.class.getName());

    public void doOperation(AuthorAccess authorAccess, ArgumentsMap argumentsMap) throws IllegalArgumentException, AuthorOperationException {
        AuthorDocumentController controller = authorAccess.getDocumentController();
        AuthorSchemaManager manager = authorAccess.getDocumentController().getAuthorSchemaManager();
        AuthorTableAccess tableContainer = authorAccess.getTableAccess();

        int selStart = authorAccess.getEditorAccess().getSelectionStart();
        int selEnd = authorAccess.getEditorAccess().getSelectionEnd();
        int initialPosition = authorAccess.getEditorAccess().getCaretOffset();

        if (authorAccess.getEditorAccess().hasSelection()){
            try{
                AuthorNode startNode = controller.getNodeAtOffset(selStart);
                while (!startNode.getName().equals("ячейка"))
                    startNode = startNode.getParent();
                AuthorNode endNode = controller.getNodeAtOffset(selEnd);
                while (!endNode.getName().equals("ячейка"))
                    endNode = endNode.getParent();

                AuthorDocumentFragment fragment = controller.createDocumentFragment(startNode.getStartOffset(), endNode.getEndOffset());
                String xmlFragment = controller.serializeFragmentToXML(fragment);
                //only for well formed xml fragment
                //must have only one root element
                xmlFragment = "<fragment>" + xmlFragment + "</fragment>";

                Document XMLDoc = null;
                Element rootTable = null;
                DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                try {
                    DocumentBuilder db = dbf.newDocumentBuilder();
                    XMLDoc = db.parse(new ByteArrayInputStream(xmlFragment.getBytes("UTF-8")));

                    //check to trust selection
                    //join only in row
                    NodeList rows = XMLDoc.getElementsByTagName("строка");
                    if (rows.getLength() > 0){
                        authorAccess.getWorkspaceAccess().showErrorMessage("Оперция объединения ячеек в строке не поддерживает объединение ячеек из разных строк");
                        return;
                    }

                    NodeList cells = XMLDoc.getElementsByTagName("ячейка");
                    Node mainCell = cells.item(0);
                    int colspan = 0;
                    for (int x = 0; x < cells.getLength(); x++){
                        Element cell = (Element) cells.item(x);
                        if (cell.hasAttribute("colspan")){
                            String collspanString = cell.getAttribute("colspan");
                            colspan += Integer.valueOf(collspanString);
                        }else
                            colspan++;
                    }
                    ((Element) mainCell).setAttribute("colspan", String.valueOf(colspan));

                    for (int x = 1; x < cells.getLength(); x++){
                        Node cell = cells.item(x);
                        NodeList cellChilds = cell.getChildNodes();
                        for (int i = 0; i < cellChilds.getLength(); i++)
                            mainCell.appendChild(cellChilds.item(i));
                    }

                    ((Element) mainCell).removeAttribute("xmlns:xsi");

                    OutputFormat opfrmt = new OutputFormat(XMLDoc, "UTF-8", false);
                    opfrmt.setPreserveSpace(false);
                    opfrmt.setOmitDocumentType(true);
                    opfrmt.setOmitXMLDeclaration(true);
                    StringWriter stringOut = new StringWriter();
                    XMLSerializer serial = new XMLSerializer(stringOut, opfrmt);
                    try {
                        serial.asDOMSerializer();
                        serial.serialize(mainCell);
                        String xmlString = stringOut.toString();

                        if (!xmlString.isEmpty()) {
                            try {

                                controller.beginCompoundEdit();

                                int pos = startNode.getStartOffset();

                                controller.delete(startNode.getStartOffset(), endNode.getEndOffset());

                                controller.insertXMLFragment(xmlString, pos);

                            } finally {

                                controller.endCompoundEdit();
                                authorAccess.getEditorAccess().setCaretPosition(selStart);

                            }
                        }
                    } catch (java.io.IOException ioe) {
                        logger.error(ioe.getLocalizedMessage());
                    }

                } catch (ParserConfigurationException e1) {
                    logger.error(e1.getLocalizedMessage());
                } catch (SAXException e1) {
                    logger.error(e1.getLocalizedMessage());
                } catch (IOException e1) {
                    logger.error(e1.getLocalizedMessage());
                } catch (NumberFormatException e1) {
                    logger.error(e1.getLocalizedMessage());
                } catch (Exception e1) {
                    logger.error(e1.getLocalizedMessage());
                }

            }catch (Exception e){
                authorAccess.getWorkspaceAccess().showErrorMessage(e.getLocalizedMessage());
            }
        }

    }

    public ArgumentDescriptor[] getArguments() {
        return new ArgumentDescriptor[0];
    }

    public String getDescription() {
        return null;
    }
}
